package etxt2db.minorthird;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import edu.cmu.minorthird.text.MonotonicTextLabels;
import edu.cmu.minorthird.text.NestedTextLabels;
import edu.cmu.minorthird.text.Span;
import edu.cmu.minorthird.text.TextLabels;
import edu.cmu.minorthird.text.mixup.Mixup;
import edu.cmu.minorthird.text.mixup.MixupInterpreter;
import edu.cmu.minorthird.text.mixup.MixupProgram;


public class MultiClassBeginContinueEndUniqueReduction extends
		MultiClassExtraction2TaggingReduction implements Serializable {

	private static final long serialVersionUID=1;

	// saves result of last reduction
	transient private NestedTextLabels taggedLabels;

	private Set<String> tokenProps = new HashSet<String>();

	// all tag values that were used
	private Set<String> tagset=new HashSet<String>();


	public void reduceExtraction2Tagging(MultiClassAnnotationExample example){
		reduceDocument(example.getDocumentSpan(),example.getLabels(),example.getInputTypes());
	}

	private void reduceDocument(Span doc,TextLabels labels,List<String> spanTypes){
		taggedLabels=new NestedTextLabels(labels);
		// label all tokens as NEG
		tokenProps.addAll(spanTypes);
		for(String spanType : tokenProps) {
			assignDefaultLabels(doc,taggedLabels,spanType);
			// label the tokens inside a span to be extracted as POS, if there's just one
			// type to extract, or with the property value, otherwise.
			String id=doc.getDocumentId();
			Iterator<Span> i= taggedLabels.instanceIterator(spanType,id);
			while(i.hasNext()){
				Span span=i.next();
				String baseTag=spanType;
				tagset.add(baseTag);
				if(span.size()==0){
					throw new IllegalStateException("empty span "+span);
				}
				if(span.size()==1){
					String tag=baseTag+"Unique";
					taggedLabels.setProperty(span.getToken(0),spanType,tag);
				}else{
					String beginTag=baseTag+"Begin";
					taggedLabels.setProperty(span.getToken(0),spanType,beginTag);
					String endTag=baseTag+"End";
					taggedLabels.setProperty(span.getToken(span.size()-1),spanType,endTag);
					if(span.size()>2){
						String contTag=baseTag+"Continue";
						for(int j=1;j<span.size()-1;j++){
							taggedLabels.setProperty(span.getToken(j),spanType,contTag);
						}
					}
				}
			}
		}
	}

	public List<String> getTokenProp(){
		return new ArrayList<String>(tokenProps);
	}

	public Set<String> getNonDefaultTagValues(){
		Set<String> result=new HashSet<String>();
		for(Iterator<String> i=tagset.iterator();i.hasNext();){
			String baseTag=i.next();
			result.add(baseTag+"Unique");
			result.add(baseTag+"Begin");
			result.add(baseTag+"End");
			result.add(baseTag+"Continue");
		}
		return result;
	}

	public TextLabels getTaggedLabels(){
		return taggedLabels;
	}

	/** Return a TextLabels in which tagged tokens are used 
	 * to solve the extraction problem. */
	public void extractFromTags(List<String> output, MonotonicTextLabels labels){
		try{
			MixupProgram p=new MixupProgram();
			for(String type : output){
				p.addStatement("defSpanType "+type+" =: "+makePattern(type,type));
			}
			MixupInterpreter interp=new MixupInterpreter(p);
			interp.eval(labels);
		}catch(Mixup.ParseException ex){
			throw new IllegalStateException("mixup error: "+ex);
		}
	}

	private String makePattern(String baseTag, String prop){
		String p=prop+":"+baseTag;
		return "... ["+p+"Begin L "+p+"Continue* R "+p+"End] ... || ... ["+p+
				"Unique] ...";
	}

}
